{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 依赖倒转原则\n",
    "\n",
    "依赖倒转原则，主要包括两点:\n",
    "\n",
    "- 抽象不应该依赖细节，细节应该依赖于抽象；\n",
    "- 高层模块不应该依赖底层模块，二者都应该依赖抽象；\n",
    "\n",
    "也就是说针对接口编程，不要对实现编程。例如一个数据库信息管理系统，数据库连接属于低层模块，增删改查等操作属于高层模块，系统界面属于更高层的模块。不同层级的模块都应该依赖于抽象，也就是接口或者抽象类，只要接口稳定，那么任何一个的更改都不用担心其他受影响，这就使得无论高层模块还是低层模块都可以很容易地被复用。\n",
    "\n",
    "## 里氏代换原则\n",
    "\n",
    "子类型必须能够替换掉它们的父类型。\n",
    "\n",
    "一个软件实体如果使用的是一个父类的话，那么一定适用于其子类，而且它察觉不出父类对象和子类对象的区别。也就是说，把父类都替换成它的子类，程序的行为没有变化。\n",
    "\n",
    "例如设计一个鸟类，一个企鹅类，假设鸟类都可以飞，但是企鹅不会飞，那么企鹅是鸟么？企鹅可以继承鸟类吗？\n",
    "\n",
    "虽然直观上企鹅也是一种特殊的鸟类，但是在面向对象编程的世界里，鸟类会飞，企鹅类不会飞，也就是企鹅类不能以鸟类的身份出现，所以且不能继承鸟类。\n",
    "\n",
    "只有当子类可以替换掉父类，软件单位的功能不受到影响时，父类才能真正被复用，而子类也能够在父类的基础上增加新的行为。正是由于子类型的可替换性才使得使用父类类型的模块在无需修改的情况下就可以扩展。\n",
    "\n",
    "## 总结\n",
    "\n",
    "依赖倒转可以说是面向对象设计的标志，用哪种语言来编写程序不重要，如果便携式考虑的都是如何针对抽象编程而不是针对细节编程，即程序中所有的依赖关系都是终止于抽象类或者接口，那就是面向对象的设计，反之就是过程化的设计了。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
